<template>
	<view
		class="popup-container"
		v-if="visibleSync"
		:style="[customStyle, {'zIndex': _zIndex - 1}]"
		:class="{ 'popup-visible': showPopup }"
		hover-stop-propagation
	>
		<page-mask :show="showPopup && mask" :custom-style="maskCustomStyle" :mask-click-able="maskCloseAble" :z-index="_zIndex - 2" @click="maskClick"></page-mask>
		<view
			class="drawer-content"
			:class="[
				safeAreaInsetBottom ? 'safe-area-inset-bottom' : '',
				'drawer-' + mode,
				showPopup ? 'drawer-content-visible' : '',
				zoom && mode === 'center' ? 'animation-zoom' : ''
			]"
			:style="[style]"
			@tap="modeCenterClose(mode)"
			@touchmove.stop.prevent
			@tap.stop.prevent
		>
			<view class="drawer-content_center" @tap.stop.prevent @touchmove.stop.prevent v-if="mode === 'center'" :style="[centerStyle]">
				<view class="drawer-close jicon-close" :class="'drawer-close_'+closeIconPos" :style="[iconStyle]" v-if="closeable" @tap="close"></view>
				<scroll-view scroll-y="true" class="drawer-scroll">
					<slot></slot>
				</scroll-view>
			</view>
			<scroll-view v-else scroll-y="true" class="drawer-scroll" :style="[scrollViewStyle]">
				<slot></slot>
			</scroll-view>
			<view class="drawer-title" v-if="title">{{ title }}</view>
			<view class="drawer-close" :class="'drawer-close_'+closeIconPos" v-if="mode !== 'center' && closeable" @tap="close">
				<slot name="close" v-if="$slots.close"></slot>
				<text class="jicon-close" :style="[iconStyle]" v-else></text>
			</view>
		</view>
	</view>
</template>

<script>
    const zIndex = {
    	mask: 998,
    	popup: 999,
    	loading: 998,
    	navbar: 997
    }
	export default {
		name: 'componentPopup',
		data() {
			return {
				visibleSync: false,
				showPopup: false,
				closeFromInner: false,
				timer: null
			}
		},
		props: {
			value: Boolean,
			// left|right|top|bottom|center
			mode: {
				type: String,
				default: 'right'
			},
			title: String,
			zoom: {
				type: Boolean,
				default: true
			},
			zIndex: {
				type: [Number, String],
				default: ''
			},
			customStyle: {
				type: Object,
				default() {
					return {};
				}
			},
			width: {
				type: String,
				default: ''
			},
			height: {
				type: String,
				default: ''
			},
			length: {
				type: [Number, String],
				default: 'auto'
			},
			borderRadius: {
				type: [Number, String],
				default: 0
			},
			background: {
				type: String,
				default: '#ffffff'
			},
			// 遮罩层
			mask: {
				type: Boolean,
				default: true
			},
			maskCloseAble: {
				type: Boolean,
				default: true
			},
			maskCustomStyle: {
				type: Object,
				default() {
					return {}
				}
			},
			// 关闭图标
			closeable: Boolean,
			// top-left | top-right | bottom-left | bottom-right
			closeIconPos: {
				type: String,
				default: 'top-right'
			},
			closeIconColor: {
				type: String,
				default: '#b4b4b4'
			},
			closeIconSize: {
				type: [String, Number],
				default: '30'
			},
			// 是否开启底部安全区适配，开启的话，会在iPhoneX机型底部添加一定的内边距
			safeAreaInsetBottom: {
				type: Boolean,
				default: false
			},
			popup: {
				type: Boolean,
				default: true
			},
			negativeTop: {
				type: [String, Number],
				default: 0
			},
			paddingNavBar: Boolean
		},
		computed: {
			style() {
				let style = {}
				// 弹出层尺寸及隐藏
				if (this.mode === 'left' || this.mode === 'right') {
					style = {
						width: this.width ? this.getUnitValue(this.width) : this.getUnitValue(this.length),
						height: '100%',
						transform: `translate3D(${this.mode === 'left' ? '-100%' : '100%'}, 0px, 0px)`
					}
				} else if (this.mode === 'top' || this.mode === 'bottom') {
					style = {
						width: '100%',
						height: this.height ? this.getUnitValue(this.height) : this.getUnitValue(this.length),
						transform: `translate3D(0px, ${this.mode === 'top' ? '-100%' : '100%'}, 0px)`
					}
				}
				// 弹出层层级
				style.zIndex = this.zIndex
				if (this.mode !== 'center') {
					style.background = this.background
				}
				// 弹出层圆角
				if (this.borderRadius) {
					switch (this.mode){
						case 'left':
							style.borderRadius = `0 ${this.borderRadius}rpx ${this.borderRadius}rpx 0`;
							break;
						case 'top':
							style.borderRadius = `0 0 ${this.borderRadius}rpx ${this.borderRadius}rpx`;
							break;
						case 'right':
							style.borderRadius = `${this.borderRadius}rpx 0 0 ${this.borderRadius}rpx`;
							break;
						case 'bottom':
							style.borderRadius = `${this.borderRadius}rpx ${this.borderRadius}rpx 0 0`;
							break;
						default:
							break;
					}
					style.overflow = 'hidden'
				}
				return style
			},
			centerStyle() {
				let style = {}
				style.width = this.width ? this.getUnitValue(this.width) : this.getUnitValue(this.length)
				style.height = this.height ? this.getUnitValue(this.height) : 'auto'
				style.zIndex = this._zIndex
				style.marginTop = `-${this.getUnitValue(this.negativeTop)}`
				style.background = this.background
				if (this.borderRadius) {
					style.borderRadius = `${this.borderRadius}rpx`
					style.overflow = 'hidden'
				}
				return style
			},
			iconStyle() {
				return {
					'font-size': this.closeIconSize + 'rpx',
					'color': this.closeIconColor
				}
			},
			scrollViewStyle () {
				let style = {}
				if (this.mode === 'top' || this.mode === 'bottom') {
					style['max-height'] = '100vh'
				}
				if (this.title) {
					style['padding-top'] = '80rpx'
				}
				if (this.paddingNavBar) {
					let navbarHeight
					// #ifdef APP-PLUS || H5
					navbarHeight = 44
					// #endif
					// #ifdef MP
					navbarHeight = uni.getSystemInfoSync().platform == 'ios' ? 44 : 48
					// #endif
					let statusBarHeight = uni.getSystemInfoSync().statusBarHeight
					style['padding-top'] = navbarHeight + statusBarHeight + 'px'
					if (this.title) {
						style['padding-top'] = uni.upx2px('80rpx') + navbarHeight + statusBarHeight + 'px'
					}
				}
				return style
			},
			_zIndex() {
				return this.zIndex || this.paddingNavBar ? 996 : zIndex.popup
			}
		},
		watch: {
			// 显示状态改变
			value(val) {
				if (val) {
					this.open()
				} else if(!this.closeFromInner) {
					// 判断改变是否来自内部，避免重复执行close()
					this.close()
				}
				this.closeFromInner = false
			}
		},
		mounted() {
			// 组件渲染完成时，检查value是否为true
			this.value && this.open()
		},
		methods: {
			// 判断传入的值是否带有单位，没有默认使用rpx
			getUnitValue(val) {
				if(/(%|px|rpx|auto)$/.test(val))
					return val
				else
					return val + 'rpx'
			},
			maskClick() {
				this.close()
			},
			open() {
				this.change('visibleSync', 'showPopup', true)
			},
			close() {
				// 标记关闭事件，避免重复执行
				this.closeFromInner = true
				this.change('showPopup', 'visibleSync', false)
			},
			change(param1, param2, status) {
				if (this.popup == true) {
					this.$emit('input', status);
				}
				// 打开时，先渲染组件，延时遮罩和弹窗动画
				// 关闭时，先执行遮罩和弹窗消失动画，再移除组件
				this[param1] = status
				if (status) {
					// #ifdef H5 || MP
					this.timer = setTimeout(() => {
						this[param2] = status
						this.$emit('open')
					}, 50);
					// #endif
					// #ifndef H5 || MP
					this.$nextTick(() => {
						this[param2] = status
						this.$emit('open')
					})
					// #endif
				} else{
					this.timer = setTimeout(() => {
						this[param2] = status
						this.$emit('close')
					}, 200);
				}
			},
			modeCenterClose(mode) {
				if (mode != 'center' || !this.maskCloseAble) return;
				this.close();
			}
		}
	}
</script>

<style scoped lang="scss">
	.popup-container {
		display: block;
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		overflow: hidden;
		.drawer-content {
			position: absolute;
			z-index: 1100;
			transition: all .2s linear;
			&.drawer-left {
				top: 0;
				bottom: 0;
				left: 0;
				background-color: #fff;
			}
			&.drawer-right {
				top: 0;
				bottom: 0;
				right: 0;
				background-color: #fff;
			}
			&.drawer-top {
				top: 0;
				left: 0;
				right: 0;
				background-color: #fff;
			}
			&.drawer-bottom {
				bottom: 0;
				left: 0;
				right: 0;
				background-color: #fff;
			}
			&.drawer-content-visible {
				transform: translate3d(0, 0, 0) !important;
			}
			&.drawer-center {
				display: flex;
				flex-direction: column;
				bottom: 0;
				left: 0;
				right: 0;
				top: 0;
				justify-content: center;
				align-items: center;
				opacity: 0;
				z-index: 1100;
			}
			&.animation-zoom {
				transform: scale(1.15);
			}
			&.drawer-content-visible.drawer-center {
				transform: scale(1);
				opacity: 1;
			}
			.drawer-content_center {
				min-width: 100rpx;
				min-height: 100rpx;
				position: relative;
				background-color: #fff;
			}
			.drawer-scroll {
				width: 100%;
				height: 100%;
			}
		}
		.drawer-title {
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			background-color: #fff;
			display: flex;
			align-items: center;
			justify-content: center;
			color: #333;
			font-weight: bold;
			height: 100rpx;
		}
		.drawer-close {
			position: absolute;
			z-index: 3;
			&.drawer-close_top-left {
				top: 30rpx;
				left: 30rpx;
			}
			&.drawer-close_top-right {
				top: 30rpx;
				right: 30rpx;
			}
			&.drawer-close_bottom-left {
				bottom: 30rpx;
				left: 30rpx;
			}
			&.drawer-close_bottom-right {
				bottom: 30rpx;
				right: 30rpx;
			}
		}
	}
</style>
